#ifndef _COMMON_H_
#define _COMMON_H_

#include <string.h>

////////////////////////////////////////////////////////////////////////////////

typedef char int8;
typedef short int16;
typedef int int32;

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned uint32;

////////////////////////////////////////////////////////////////////////////////

void Rand_init();
int Rand_int();
int Rand_int(int max);
int Rand_int(int min,int max);
float Rand_float();
float Rand_float(float min,float max);
bool Rand_chance(float p);

////////////////////////////////////////////////////////////////////////////////

template<typename Data>
class Array
{
  public:
  Array(unsigned size)
  {
    _size = size;
    _data = new Data[size];
  }
  ~Array()
  {
    delete[] _data;
  }
  
  int size() const {return _size;}
  int length() const {return _size;}
  
  const Data& operator[](int index) const
  {
    return _data[index];
  }
  Data& operator[](int index)
  {
    return _data[index];
  }
  
  void deleteAll()
  {
    for (int i = 0; i < _size; i++)
    {
      delete _data[i];
    }
  }
  
  private:
  int _size;
  Data* _data;
};

////////////////////////////////////////////////////////////////////////////////

template<typename Data>
class List
{
  public:
  List()
  {
    _size = 0;
    _max_size = 0;
    _step = 16;
    _data = NULL;
  }
  ~List()
  {
    delete[] _data;
  }
  
  void insert(const Data& data)
  {
    if (_size >= _max_size)
    {
      _max_size += _step;
      
      Data* new_data = new Data[_max_size];
      
      memcpy(new_data, _data, sizeof(Data) * _size);
      
      delete[] _data;
      
      _data = new_data;
    }
    
    _data[_size++] = data;
  }
  void remove(int index)
  {
    _size--;
    
    for (int i = index ; i < _size; i++)
    {
      _data[i] = _data[i + 1];
    }
  }
  void removeVal(const Data& d)
  {
    for (int i = 0; i < _size; i++)
    {
      if (_data[i] == d)
      {
        remove(i);
        
        return;
      }
    }
  }
  int length() const {return _size;}
  const Data& operator[](int index) const
  {
    return _data[index];
  }
  Data& operator[](int index)
  {
    return _data[index];
  }
  bool contains(const Data& d)
  {
    for (int i = 0; i < _size; i++)
    {
      if (_data[i] == d)
      {
        return true;
      }
    }
    
    return false;
  }
  void deleteAll()
  {
    for (int i = 0; i < _size; i++)
    {
      delete _data[i];
    }
    
    _size = 0;
  }
  
  private:
  int _size, _max_size, _step;
  Data* _data;
};

////////////////////////////////////////////////////////////////////////////////

template<typename Data, int MAX_SIZE>
class Stack
{
  public:
  Stack(): _size(0) {}
  
  bool canPush() const {return _size < MAX_SIZE;}
  bool canPop() const {return _size > 0;}
  
  void push(const Data& data)
  {
    _data[_size++] = data;
  }
  Data& pop()
  {
    return _data[--_size];
  }
  Data& top()
  {
    return _data[_size - 1];
  }
  
  private:
  int _size;
  Data _data[MAX_SIZE];
};

////////////////////////////////////////////////////////////////////////////////

template<typename Data, int MAX_SIZE>
class Queue
{
  public:
  Queue(): _first(0), _size(0) {}
  
  bool canGet() const {return _size > 0;}
  bool canPut() const {return _size < MAX_SIZE;}
  
  void put(const Data& data)
  {
    unsigned index = (_first + (++_size)) % MAX_SIZE;
    
    _data[index] = data;
  }
  Data& get()
  {
    unsigned index = ((_first++) + (_size--)) % MAX_SIZE;
    
    return _data[index];
  }
  
  private:
  unsigned _first;
  unsigned _size;
  Data _data[MAX_SIZE];
};

////////////////////////////////////////////////////////////////////////////////

class String
{
  public:
  String(): _str(NULL) {}
  String(const char* str)
  {
    _str = new char[strlen(str) + 1];
    
    strcpy(_str, str);
  }
  String(const String& str)
  {
     _str = new char[strlen(str._str) + 1];
    
    strcpy(_str, str._str);
  }
  
  const char* str() const {return _str;}
  
  private:
  char* _str;
};

////////////////////////////////////////////////////////////////////////////////

class Point
{
  public:
  Point() {}
  Point(int x, int y):
    x(x), y(y) {}
  
  void set(int x, int y) {this->x = x; this->y = y;}
  
  int x, y;
};

inline Point operator-(const Point& p1, const Point& p2)
{
  return Point(p1.x - p2.x, p1.y - p2.y);
}

class Dimension
{
  public:
  Dimension(){}
  Dimension(int w, int h):
    w(w), h(h) {}
  
  void set(int w, int h) {this->w = w; this->h =h;}
  
  int w, h;
};

////////////////////////////////////////////////////////////////////////////////

class Rect
{
  public:
  Rect() {}
  Rect(int x, int y, int w, int h)
  {
    this->x = x;
    this->y = y;
    this->w = w;
    this->h = h;
  }
    
  void set(int x, int y, int w, int h)
  {
    this->x = x;
    this->y = y;
    this->w = w;
    this->h = h;
  }
  
  void centerIn(const Rect& r);
  bool intersect(const Point& p) const;
    
  int x, y, w, h;
};

////////////////////////////////////////////////////////////////////////////////

class IdGen
{
  public:
  bool isId(unsigned id);
  unsigned genId();
  void delId(unsigned id);
  
  private:
  List<unsigned> _ids;
};

#endif
